﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Security;
using System.Runtime.Serialization;
using System.Collections.ObjectModel;

namespace Djs.Common.Components
{
    #region CollectIdx<T> kolekce dat s dvojitým indexem podle item.Id a item.Key
    /// <summary>
    /// Kolekce dat s dvojitým indexem podle int item.Id a string item.Key.
    /// Hodnota klíče string Key je case-insensitive.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CollectIdx<T> : IEnumerable<T>, IDisposable where T : IIdKey
    {
        #region Konstrukce
        public CollectIdx()
        {
            this.DisableKeyLogic = false;
            this.DataId = new DictionaryEvnt<int, T>();
            this.DataKey = new DictionaryEvnt<string, T>();
        }
        /// <summary>
        /// Konstruktor.
        /// Umožní zakázat tvorbu indexu podle string Key, když chceme povolit více shodných Key.
        /// Pak nelze podle Key vyhledávat.
        /// </summary>
        /// <param name="disableKeyLogic">Zákaz indexování podle string Key</param>
        public CollectIdx(bool disableKeyLogic)
        {
            this.DisableKeyLogic = disableKeyLogic;
            this.DataId = new DictionaryEvnt<int, T>();
            if (!disableKeyLogic)
                this.DataKey = new DictionaryEvnt<string, T>();
        }
        public override string ToString()
        {
            return "Collection of types:" + typeof(T).Name + "; ItemCount=" + this.DataId.Count + "; KeyCount=" + (DisableKeyLogic ? "disabled" : this.DataKey.Count.ToString());
        }
        /// <summary>
        /// Zákaz indexování podle string Key. Nastavit lze pouze v konstruktoru.
        /// </summary>
        public bool DisableKeyLogic { get; protected set; }
        /// <summary>
        /// Hlavní Dictionary, obsahuje všechny položky, dle int Id
        /// </summary>
        protected DictionaryEvnt<int, T> DataId { get; private set; }
        /// <summary>
        /// Vedlejší Dictinary, obsahuje pouze ty položky, které mají string Key.
        /// Používá se jen tehdy, pokud není zakázaná Key logika (this.DisableKeyLogic).
        /// </summary>
        protected DictionaryEvnt<string, T> DataKey { get; private set; }
        #endregion
        #region Imitace Dictionary a Listu
        /// <summary>
        /// Počet vět
        /// </summary>
        public int Count { get { return this.DataId.Count; } }
        /// <summary>
        /// Přidá větu
        /// </summary>
        /// <param name="value"></param>
        public void Add(T value)
        {
            this.DataId.Add(value.Id, value);
            string k = FormatThisKey(value.Key);
            if (!String.IsNullOrEmpty(k))
                this.DataKey.Add(k, value);
        }
        /// <summary>
        /// Přidá řadu vět
        /// </summary>
        /// <param name="values"></param>
        public void Add(params T[] values)
        {
            foreach (T value in values)
                this.Add(value);
        }
        /// <summary>
        /// Přidá pole vět
        /// </summary>
        /// <param name="list"></param>
        public void AddRange(IEnumerable<T> list)
        {
            foreach (T value in list)
                this.Add(value);
        }
        /// <summary>
        /// Test, zda kolekce již obsahuje větu (podle klíče Id)
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool ContainsKey(T value)
        {
            return this.DataId.ContainsKey(value.Id);
        }
        /// <summary>
        /// Test, zda kolekce již obsahuje větu (podle klíče Id)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool ContainsKey(int id)
        {
            return this.DataId.ContainsKey(id);
        }
        /// <summary>
        /// Test, zda kolekce již obsahuje větu (podle klíče Key)
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(string key)
        {
            string k = FormatThisKey(key);
            if (k == null) return false;
            return this.DataKey.ContainsKey(k);
        }
        /// <summary>
        /// Zkusí najít větu podle klíče Id
        /// </summary>
        /// <param name="id"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValue(int id, out T value)
        {
            return this.DataId.TryGetValue(id, out value);
        }
        /// <summary>
        /// Zkusí najít větu podle klíče Key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValue(string key, out T value)
        {
            string k = FormatThisKey(key);
            if (k == null)
            {
                value = default(T);
                return false;
            }
            return this.DataKey.TryGetValue(k, out value);
        }
        /// <summary>
        /// Vrátí větu podle klíče Id.
        /// Pokud neexistuje, vyhodí chybu.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public T this[int id]
        {
            get { return this.DataId[id]; }
        }
        /// <summary>
        /// Vrátí větu podle klíče Key.
        /// Pokud neexistuje, vyhodí chybu.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T this[string key]
        {
            get
            {
                string k = FormatThisKey(key);
                if (k == null) return default(T);
                return this.DataKey[k];
            }
        }
        /// <summary>
        /// Odebere větu podle klíče Id
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Remove(T value)
        {
            return this.Remove(value.Id);
        }
        /// <summary>
        /// Odebere větu podle klíče Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Remove(int id)
        {
            T value;
            if (this.TryGetValue(id, out value))
            {
                this.DataId.Remove(id);
                if (!String.IsNullOrEmpty(value.Key) && this.DataKey.ContainsKey(value.Key))
                    this.DataKey.Remove(value.Key);
                return true;
            }
            return false;
        }
        /// <summary>
        /// Odebere větu podle klíče Key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Remove(string key)
        {
            string k = FormatThisKey(key);
            T value;
            if (!String.IsNullOrEmpty(k) && this.DataKey.TryGetValue(k, out value))
            {
                this.DataKey.Remove(k);
                if (this.DataId.ContainsKey(value.Id))
                    this.DataId.Remove(value.Id);
                return true;
            }
            return false;
        }
        /// <summary>
        /// Vyprázdní celou kolekci
        /// </summary>
        public void Clear()
        {
            this.DataId.Clear();
            if (!this.DisableKeyLogic)
                this.DataKey.Clear();
        }
        #endregion
        #region Přidané funkce
        /// <summary>
        /// Vrátí seznam položek, netříděný (v pořadí přidávání).
        /// Seznam je nově vytvořený objekt, který není závislý na interních datech CollectIdx.
        /// </summary>
        public List<T> List
        {
            get
            {
                List<T> result = new List<T>(this.DataId.Values);
                return result;
            }
        }
        /// <summary>
        /// Vrátí seznam položek, tříděný dle hodnoty Key
        /// </summary>
        public List<T> SortedList
        {
            get
            {
                List<T> result = new List<T>(this.DataId.Values);
                result.Sort(delegate(T a, T b) { return String.Compare(a.Key, b.Key, true); });
                return result;
            }
        }
        /// <summary>
        /// Formátuje klíč (vrací null, anebo key.Trim().ToLower();)
        /// Vrací null, pokud je zakázaná logika Key (DisableKeyLogic je true).
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected string FormatThisKey(string key)
        {
            if (this.DisableKeyLogic) return null;
            if (string.IsNullOrEmpty(key)) return null;
            return key.Trim().ToLower();
        }
        /// <summary>
        /// Formátuje klíč (vrací null, anebo key.Trim().ToLower();)
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string FormatKey(string key)
        {
            if (string.IsNullOrEmpty(key))
                return null;
            return key.Trim().ToLower();
        }
        #endregion
        #region IEnumerable<T> + IEnumerable Members. Dovolí snadno enumerovat seznamem.
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return this.DataId.Values.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.DataId.Values.GetEnumerator();
        }
        public void Dispose()
        {
            this.Clear();
        }
        void IDisposable.Dispose()
        {
            this.Dispose();
        }
        #endregion
    }
    #endregion
    #region Interface, který garantuje přítomnost property int Id a string Key.
    /// <summary>
    /// Interface, který garantuje přítomnost property int Id a string Key.
    /// Používá se pro objekty, které mohou být ukládány do dvojindexové kolekce CollectIdx.
    /// </summary>
    public interface IIdKey
    {
        int Id { get; }
        string Key { get; }
    }
    #endregion
    #region DictionaryEvnt : Dictionary, která poskytuje eventy při změnách
    /// <summary>
    /// DictionaryEvnt : adaptér na Dictionary.
    /// Poskytuje eventy při změnách.
    /// Obsahuje neviditelnou cache na poslední nalezenou hodnotu - pro urychlení opakovaného hledání téhož klíče.
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    public class DictionaryEvnt<TKey, TValue> : IEnumerable<TValue>, IEnumerable
    {
        #region Konstrukce
        protected Dictionary<TKey, TValue> Dict;
        public override string ToString()
        {
            return "DictionaryEvnt<" + typeof(TKey).GetType().Name + ", " + typeof(TValue).GetType().Name + ">; ItemCount=" + this.Dict.Count.ToString();
        }
        #endregion
        #region Eventy
        public class DictionaryEventArgs : EventArgs
        {
            /// <summary>
            /// Data, o která se jedná
            /// </summary>
            public KeyValuePair<TKey, TValue> KeyValue { get; protected set; }
            /// <summary>
            /// Eventhandler může zakázat operaci
            /// </summary>
            public bool Cancel { get; set; }
        }
        /// <summary>
        /// Předpis pro metodu, která je event handlerem změn v DictionaryEvnt
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public delegate void DictionaryEventHandler(object sender, DictionaryEventArgs args);
        /// <summary>
        /// Event volaný před přidáním nové položky. 
        /// Handler může přidání zakázat. Pak se položka tiše nepřidá. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemAddBefore;
        /// <summary>
        /// Event volaný před vrácením nalezené položky. 
        /// Handler může vrácení položky zakázat. Pak se položka nevrátí, jako by se nenašla. V metodě this[] get dojde k výjimce Key not exists. V metodě TryGetValue se vrátí false.
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemGetBefore;
        /// <summary>
        /// Event volaný před vložením existující položky v metodě this[] set. 
        /// Handler může vložení zakázat. Pak se položka tiše nevloží. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemSetBefore;
        /// <summary>
        /// Event volaný před smazáním existující položky. 
        /// Handler může smazání zakázat. Pak se položka tiše nesmaže. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemRemoveBefore;
        #endregion
        #region Neviditelná cache na LastFind položku
        /// <summary>
        /// Cache: reset (po provedení změny v Dictionary.Key = po metodě Add, Remove, Clear).
        /// </summary>
        protected void LastValueReset()
        {
            this.LastExists = false;
            this.LastKey = default(TKey);
            this.LastFound = false;
            this.LastValue = default(TValue);
        }
        /// <summary>
        /// Cache: data existují, jsou uložena a platná
        /// </summary>
        protected bool LastExists;
        /// <summary>
        /// Cache: Klíč posledně hledané položky. Informace o tom, zda byla nalezena je v this.LastFind, nalezená hodnota je v this.LastValue
        /// </summary>
        protected TKey LastKey;
        /// <summary>
        /// Cache: Výsledek posledního hledání klíče this.LastKey
        /// </summary>
        protected bool LastFound;
        /// <summary>
        /// Cache: Posledně nalezená položka (=data) dle klíče LastKey
        /// </summary>
        protected TValue LastValue;
        /// <summary>
        /// Detekce: hledali jsme posledně danou hodnotu? Neřeším s jakým výsledkem (ten je v this.LastFind, hodnota je v this.LastValue).
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected bool LastValueIsForKey(TKey key)
        {
            if (key == null) return false;
            return (this.LastExists && key.Equals(this.LastKey));
        }
        /// <summary>
        /// Detekce: máme v cache nalezenou hodnotu pro hledání daného klíče?
        /// Tzn. posledně jsme hledali tentýž klíč, a data jsme našli. Můžeme vrátit LastValue.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected bool LastValueIsFindForKey(TKey key)
        {
            return (this.LastExists && key.Equals(this.LastKey) && this.LastFound);
        }
        /// <summary>
        /// Cache: uloží si hledaný klíč, výsledek a hodnotu pro příští hledání
        /// </summary>
        /// <param name="key"></param>
        /// <param name="found"></param>
        /// <param name="value"></param>
        protected void LastValueSet(TKey key, bool found, TValue value)
        {
            this.LastExists = true;
            this.LastKey = key;
            this.LastFound = found;
            this.LastValue = value;
        }
        #endregion
        #region Dictionary : přechodníky metod a property z this do this.Dict. Třída this se zvenku tváří jako Dictionary.
        /// Summary:
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that is empty, has the default initial capacity, and uses the default
        ///     equality comparer for the key type.
        public DictionaryEvnt()
        {
            this.Dict = new Dictionary<TKey, TValue>();
            this.LastValueReset();
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that contains elements copied from the specified System.Collections.Generic.IDictionary<TKey,TValue>
        ///     and uses the default equality comparer for the key type.
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     dictionary is null.
        ///
        ///   System.ArgumentException:
        ///     dictionary contains one or more duplicate keys.
        /// </summary>
        public DictionaryEvnt(IDictionary<TKey, TValue> dictionary)
        {
            this.Dict = new Dictionary<TKey, TValue>(dictionary);
            this.LastValueReset();
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that is empty, has the default initial capacity, and uses the specified
        ///     System.Collections.Generic.IEqualityComparer<T>.
        ///
        /// Parameters:
        ///   comparer:
        ///     The System.Collections.Generic.IEqualityComparer<T> implementation to use
        ///     when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
        ///     for the type of the key.
        /// </summary>
        public DictionaryEvnt(IEqualityComparer<TKey> comparer)
        {
            this.Dict = new Dictionary<TKey, TValue>(comparer);
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that is empty, has the specified initial capacity, and uses the default
        ///     equality comparer for the key type.
        ///
        /// Parameters:
        ///   capacity:
        ///     The initial number of elements that the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     can contain.
        ///
        /// Exceptions:
        ///   System.ArgumentOutOfRangeException:
        ///     capacity is less than 0.
        /// </summary>
        public DictionaryEvnt(int capacity)
        {
            this.Dict = new Dictionary<TKey, TValue>(capacity);
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that contains elements copied from the specified System.Collections.Generic.IDictionary<TKey,TValue>
        ///     and uses the specified System.Collections.Generic.IEqualityComparer<T>.
        ///
        /// Parameters:
        ///   dictionary:
        ///     The System.Collections.Generic.IDictionary<TKey,TValue> whose elements are
        ///     copied to the new System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        ///   comparer:
        ///     The System.Collections.Generic.IEqualityComparer<T> implementation to use
        ///     when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
        ///     for the type of the key.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     dictionary is null.
        ///
        ///   System.ArgumentException:
        ///     dictionary contains one or more duplicate keys.
        /// </summary>
        public DictionaryEvnt(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
        {
            this.Dict = new Dictionary<TKey, TValue>(dictionary, comparer);
        }
        /// <summary>
        ///     Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     class that is empty, has the specified initial capacity, and uses the specified
        ///     System.Collections.Generic.IEqualityComparer<T>.
        ///
        /// Parameters:
        ///   capacity:
        ///     The initial number of elements that the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     can contain.
        ///
        ///   comparer:
        ///     The System.Collections.Generic.IEqualityComparer<T> implementation to use
        ///     when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
        ///     for the type of the key.
        ///
        /// Exceptions:
        ///   System.ArgumentOutOfRangeException:
        ///     capacity is less than 0.
        /// </summary>
        public DictionaryEvnt(int capacity, IEqualityComparer<TKey> comparer)
        {
            this.Dict = new Dictionary<TKey, TValue>(comparer);
        }
        /// <summary>
        ///     Gets the System.Collections.Generic.IEqualityComparer<T> that is used to
        ///     determine equality of keys for the dictionary.
        ///
        /// Returns:
        ///     The System.Collections.Generic.IEqualityComparer<T> generic interface implementation
        ///     that is used to determine equality of keys for the current System.Collections.Generic.Dictionary<TKey,TValue>
        ///     and to provide hash values for the keys.
        /// </summary>
        public IEqualityComparer<TKey> Comparer
        { get { return this.Dict.Comparer; } }
        /// <summary>
        ///     Gets the number of key/value pairs contained in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     The number of key/value pairs contained in the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public int Count
        { get { return this.Dict.Count; } }
        /// <summary>
        ///     Gets a collection containing the keys in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     A System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection containing
        ///     the keys in the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public Dictionary<TKey, TValue>.KeyCollection Keys
        { get { return this.Dict.Keys; } }
        /// <summary>
        ///     Gets a collection containing the values in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     A System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection containing
        ///     the values in the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public Dictionary<TKey, TValue>.ValueCollection Values
        { get { return this.Dict.Values; } }
        /// <summary>
        ///     Gets or sets the value associated with the specified key.
        ///
        /// Parameters:
        ///   key:
        ///     The key of the value to get or set.
        ///
        /// Returns:
        ///     The value associated with the specified key. If the specified key is not
        ///     found, a get operation throws a System.Collections.Generic.KeyNotFoundException,
        ///     and a set operation creates a new element with the specified key.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        ///
        ///   System.Collections.Generic.KeyNotFoundException:
        ///     The property is retrieved and key does not exist in the collection.
        /// </summary>
        public TValue this[TKey key]
        {
            get
            {
                if (this.LastValueIsForKey(key))
                {   // Cache:
                    if (this.LastFound) return this.LastValue;
                    // Chyba:
                    throw new KeyNotFoundException("Key " + key.ToString() + " not found in DictionaryEvnt.");
                }
                TValue value;
                bool found = this.Dict.TryGetValue(key, out value);
                this.LastValueSet(key, found, value);
                if (found) return value;
                throw new KeyNotFoundException("Key " + key.ToString() + " not found in DictionaryEvnt.");
            }
            set
            {
                this.Dict[key] = value;
                this.LastValueReset();
            }
        }
        /// <summary>
        ///     Adds the specified key and value to the dictionary.
        ///
        /// Parameters:
        ///   key:
        ///     The key of the element to add.
        ///
        ///   value:
        ///     The value of the element to add. The value can be null for reference types.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        ///
        ///   System.ArgumentException:
        ///     An element with the same key already exists in the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public void Add(TKey key, TValue value)
        {
            this.Dict.Add(key, value);

            if (this.LastValueIsForKey(key))
                this.LastValueReset();
        }
        /// <summary>
        ///     Removes all keys and values from the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public void Clear()
        {
            this.Dict.Clear();
            this.LastValueReset();
        }
        /// <summary>
        ///     Determines whether the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     contains the specified key.
        ///
        /// Parameters:
        ///   key:
        ///     The key to locate in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
        ///     element with the specified key; otherwise, false.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        /// </summary>
        public bool ContainsKey(TKey key)
        {
            if (this.LastValueIsForKey(key))
            {   // Cache:
                return this.LastFound;
            }
            TValue value;
            bool found = this.Dict.TryGetValue(key, out value);
            this.LastValueSet(key, found, value);
            return found;
        }
        /// <summary>
        ///     Determines whether the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     contains a specific value.
        ///
        /// Parameters:
        ///   value:
        ///     The value to locate in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///     The value can be null for reference types.
        ///
        /// Returns:
        ///     true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
        ///     element with the specified value; otherwise, false.
        /// </summary>
        public bool ContainsValue(TValue value)
        {
            return this.Dict.ContainsValue(value);
        }
        /// <summary>
        ///     Returns an enumerator that iterates through the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Returns:
        ///     A System.Collections.Generic.Dictionary<TKey,TValue>.Enumerator structure
        ///     for the System.Collections.Generic.Dictionary<TKey,TValue>.
        /// </summary>
        public Dictionary<TKey, TValue>.Enumerator GetEnumerator()
        {
            return this.Dict.GetEnumerator();
        }
        /// <summary>
        ///     Implements the System.Runtime.Serialization.ISerializable interface and returns
        ///     the data needed to serialize the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     instance.
        ///
        /// Parameters:
        ///   info:
        ///     A System.Runtime.Serialization.SerializationInfo object that contains the
        ///     information required to serialize the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     instance.
        ///
        ///   context:
        ///     A System.Runtime.Serialization.StreamingContext structure that contains the
        ///     source and destination of the serialized stream associated with the System.Collections.Generic.Dictionary<TKey,TValue>
        ///     instance.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     info is null.
        /// </summary>
        [SecurityCritical]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            this.Dict.GetObjectData(info, context);
        }
        /// <summary>
        ///     Implements the System.Runtime.Serialization.ISerializable interface and raises
        ///     the deserialization event when the deserialization is complete.
        ///
        /// Parameters:
        ///   sender:
        ///     The source of the deserialization event.
        ///
        /// Exceptions:
        ///   System.Runtime.Serialization.SerializationException:
        ///     The System.Runtime.Serialization.SerializationInfo object associated with
        ///     the current System.Collections.Generic.Dictionary<TKey,TValue> instance is
        ///     invalid.
        /// </summary>
        public virtual void OnDeserialization(object sender)
        { }
        /// <summary>
        ///     Removes the value with the specified key from the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Parameters:
        ///   key:
        ///     The key of the element to remove.
        ///
        /// Returns:
        ///     true if the element is successfully found and removed; otherwise, false.
        ///     This method returns false if key is not found in the System.Collections.Generic.Dictionary<TKey,TValue>.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        /// </summary>
        public bool Remove(TKey key)
        {
            if (this.LastValueIsForKey(key))
                this.LastValueReset();

            return this.Dict.Remove(key);
        }
        /// <summary>
        ///     Gets the value associated with the specified key.
        ///
        /// Parameters:
        ///   key:
        ///     The key of the value to get.
        ///
        ///   value:
        ///     When this method returns, contains the value associated with the specified
        ///     key, if the key is found; otherwise, the default value for the type of the
        ///     value parameter. This parameter is passed uninitialized.
        ///
        /// Returns:
        ///     true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
        ///     element with the specified key; otherwise, false.
        ///
        /// Exceptions:
        ///   System.ArgumentNullException:
        ///     key is null.
        /// </summary>
        public bool TryGetValue(TKey key, out TValue value)
        {
            if (this.LastValueIsForKey(key))
            {   // Cache:
                value = this.LastValue;
                return this.LastFound;
            }
            bool found = this.Dict.TryGetValue(key, out value);
            this.LastValueSet(key, found, value);
            return found;
        }
        #endregion
        #region IEnumerable, IEnumerable<TValue> Members Members
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.Dict.Values.GetEnumerator();
        }
        IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
        {
            return this.Dict.Values.GetEnumerator();
        }
        #endregion
    }
    #endregion
    #region ListEvnt : List, který poskytuje eventy při změnách
    /// <summary>
    /// ListEvnt : adaptér na List.
    /// Poskytuje eventy při změnách.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ListEvnt<T> : IEnumerable<T>, IEnumerable
    {
        #region Eventy
        /// <summary>
        /// Data for events in ListEvnt class
        /// </summary>
        public class ListEventArgs : EventArgs
        {
            public ListEventArgs(ListChangeType changeType)
            {
                this.ChangeType = changeType;
                this.Item = default(T);
                this.Index = null;
                this.Cancel = false;
            }
            public ListEventArgs(ListChangeType changeType, T item)
            {
                this.ChangeType = changeType;
                this.Item = item;
                this.Index = null;
                this.Cancel = false;
            }
            public ListEventArgs(ListChangeType changeType, Int32? index)
            {
                this.ChangeType = changeType;
                this.Item = default(T);
                this.Index = index;
                this.Cancel = false;
            }
            public ListEventArgs(ListChangeType changeType, T item, Int32? index)
            {
                this.ChangeType = changeType;
                this.Item = item;
                this.Index = index;
                this.Cancel = false;
            }
            /// <summary>
            /// Typ změny, o kterou se jedná
            /// </summary>
            public ListChangeType ChangeType { get; protected set; }
            /// <summary>
            /// Data, o která se jedná
            /// </summary>
            public T Item { get; protected set; }
            /// <summary>
            /// Pozice dat, o kterou se jedná
            /// </summary>
            public Int32? Index { get; protected set; }
            /// <summary>
            /// Eventhandler může zakázat operaci
            /// </summary>
            public bool Cancel { get; set; }
        }
        /// <summary>
        /// Event volaný před přidáním nové položky. 
        /// Handler může přidání zakázat. Pak se položka tiše nepřidá. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event ListEventHandler ItemAddBefore;
        /// <summary>
        /// Event volaný po přidání nové položky. 
        /// </summary>
        public event ListEventHandler ItemAddAfter;
        /// <summary>
        /// Event volaný před vrácením nalezené položky. 
        /// Handler může vrácení položky zakázat. Pak se položka nevrátí, jako by se nenašla. V metodě this[] get dojde k výjimce Key not exists.
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event ListEventHandler ItemGetBefore;
        /// <summary>
        /// Event volaný před vložením existující položky v metodě this[] set. 
        /// Handler může vložení zakázat. Pak se položka tiše nevloží. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event ListEventHandler ItemSetBefore;
        /// <summary>
        /// Event volaný po vložení položky (this[] = item).
        /// </summary>
        public event ListEventHandler ItemSetAfter;
        /// <summary>
        /// Event volaný před smazáním existující položky. 
        /// Handler může smazání zakázat. Pak se položka tiše nesmaže. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event ListEventHandler ItemRemoveBefore;
        /// <summary>
        /// Event volaný po smazání existující položky. 
        /// </summary>
        public event ListEventHandler ItemRemoveAfter;
        /// <summary>
        /// Event volaný před jakoukoli změnou položek (kromě Get).
        /// Tento event je volán i před změnami typu Sort, Reverse, Clear, které nemají svůj speciální handler.
        /// Handler může akci zakázat. Pak se tiše nic nestane. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event ListEventHandler ListChangeBefore;
        /// <summary>
        /// Event volaný po smazání existující položky. 
        /// </summary>
        public event ListEventHandler ListChangeAfter;
        /// <summary>
        /// Předpis pro metodu, která je event handlerem změn v ListEvnt
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public delegate void ListEventHandler(object sender, ListEventArgs args);
        #endregion
        #region Protected podpora eventů
        protected virtual bool CanAddItem(T item)
        {
            bool result = true;
            if (this.ItemAddBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Add, item);
                this.ItemAddBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            if (this.ListChangeBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Add, item);
                this.ListChangeBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            return result;
        }
        protected virtual bool CanAddItem(T item, Int32? index)
        {
            bool result = true;
            if (this.ItemAddBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Add, item, index);
                this.ItemAddBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            if (this.ListChangeBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Add, item, index);
                this.ListChangeBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            return result;
        }
        protected virtual void OnAddItemAfter(T item)
        {
            if (this.ItemAddAfter != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Add, item);
                this.ItemAddAfter(this, args);
            }
            if (this.ListChangeAfter != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Add, item);
                this.ListChangeAfter(this, args);
            }
        }
        protected virtual void OnAddItemAfter(T item, Int32? index)
        {
            if (this.ItemAddAfter != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Add, item, index);
                this.ItemAddAfter(this, args);
            }
            if (this.ListChangeAfter != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Add, item, index);
                this.ListChangeAfter(this, args);
            }
        }
        protected virtual bool CanGetItem(T item, Int32? index)
        {
            bool result = true;
            if (this.ItemGetBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Get, item, index);
                this.ItemGetBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            return result;
        }
        protected virtual void OnGetItemAfter(T item, Int32? index)
        {
        }
        protected virtual bool CanSetItem(T item, Int32? index)
        {
            bool result = true;
            if (this.ItemSetBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Set, item, index);
                this.ItemSetBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            if (this.ListChangeBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Set, item, index);
                this.ListChangeBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            return result;
        }
        protected virtual void OnSetItemAfter(T item, Int32? index)
        {
            if (this.ItemSetAfter != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Set, item, index);
                this.ItemSetAfter(this, args);
            }
            if (this.ListChangeAfter != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Set, item, index);
                this.ListChangeAfter(this, args);
            }
        }
        protected virtual bool CanRemoveItem(T item, Int32? index)
        {
            bool result = true;
            if (this.ItemRemoveBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Remove, item, index);
                this.ItemRemoveBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            if (this.ListChangeBefore != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Remove, item, index);
                this.ListChangeBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            return result;
        }
        protected virtual void OnRemoveItemAfter(T item, Int32? index)
        {
            if (this.ItemRemoveAfter != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Remove, item, index);
                this.ItemRemoveAfter(this, args);
            }
            if (this.ListChangeAfter != null)
            {
                ListEventArgs args = new ListEventArgs(ListChangeType.Remove, item, index);
                this.ListChangeAfter(this, args);
            }
        }
        protected virtual bool CanChangeList(ListChangeType changeType)
        {
            bool result = true;
            if (this.ListChangeBefore != null)
            {
                ListEventArgs args = new ListEventArgs(changeType);
                this.ListChangeBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            return result;
        }
        protected virtual bool CanChangeList(ListChangeType changeType, T item, Int32? index)
        {
            bool result = true;
            if (this.ListChangeBefore != null)
            {
                ListEventArgs args = new ListEventArgs(changeType, item, index);
                this.ListChangeBefore(this, args);
                if (args.Cancel)
                    result = false;
            }
            return result;
        }
        protected virtual void OnChangeListAfter(ListChangeType changeType)
        {
            if (this.ListChangeAfter != null)
            {
                ListEventArgs args = new ListEventArgs(changeType);
                this.ListChangeAfter(this, args);
            }
        }
        protected virtual void OnChangeListAfter(ListChangeType changeType, T item, Int32? index)
        {
            if (this.ListChangeAfter != null)
            {
                ListEventArgs args = new ListEventArgs(changeType, item, index);
                this.ListChangeAfter(this, args);
            }
        }
        #endregion
        #region Public List members (adapter to List)
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.List<T> class that is empty and has the default initial capacity.
        /// </summary>
        public ListEvnt()
        {
            this._List = new List<T>();
        }
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.List<T> class
        /// that contains elements copied from the specified collection and has sufficient
        /// capacity to accommodate the number of elements copied.
        /// </summary>
        /// <param name="collection">The collection whose elements are copied to the new list.</param>
        /// <exceptions>System.ArgumentNullException: collection is null.</exceptions>
        public ListEvnt(IEnumerable<T> collection)
        {
            this._List = new List<T>(collection);
        }
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.List<T> class that is empty and has the specified initial capacity.
        /// </summary>
        /// <param name="capacity">The number of elements that the new list can initially store.</param>
        /// <remarks>Exceptions: System.ArgumentOutOfRangeException: capacity is less than 0.</remarks>
        public ListEvnt(int capacity)
        {
            this._List = new List<T>(capacity);
        }
        // Summary:
        //     Gets or sets the total number of elements the internal data structure can
        //     hold without resizing.
        //
        // Returns:
        //     The number of elements that the System.Collections.Generic.List<T> can contain
        //     before resizing is required.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     System.Collections.Generic.List<T>.Capacity is set to a value that is less
        //     than System.Collections.Generic.List<T>.Count.
        //
        //   System.OutOfMemoryException:
        //     There is not enough memory available on the system.
        public int Capacity { get { return this._List.Capacity; } set { this._List.Capacity = value; } }
        //
        // Summary:
        //     Gets the number of elements actually contained in the System.Collections.Generic.List<T>.
        //
        // Returns:
        //     The number of elements actually contained in the System.Collections.Generic.List<T>.
        public int Count { get { return this._List.Count; } }

        // Summary:
        //     Gets or sets the element at the specified index.
        //
        // Parameters:
        //   index:
        //     The zero-based index of the element to get or set.
        //
        // Returns:
        //     The element at the specified index.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-index is equal to or greater than System.Collections.Generic.List<T>.Count.
        public T this[int index]
        {
            get
            {
                T item = this._List[index];
                if (this.CanGetItem(item, index))
                {
                    this.OnGetItemAfter(item, index);
                    return item;
                }
                throw new System.ArgumentOutOfRangeException("Item at index [" + index.ToString() + "] can not be retrieved.");
            }
            set
            {
                if (this.CanSetItem(value, index))
                {
                    this._List[index] = value;
                    this.OnSetItemAfter(value, index);
                }
            }
        }

        // Summary:
        //     Adds an object to the end of the System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   item:
        //     The object to be added to the end of the System.Collections.Generic.List<T>.
        //     The value can be null for reference types.
        public void Add(T item)
        {
            if (this.CanAddItem(item))
            {
                this._List.Add(item);
                this.OnAddItemAfter(item);
            }
        }
        //
        // Summary:
        //     Adds the elements of the specified collection to the end of the System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   collection:
        //     The collection whose elements should be added to the end of the System.Collections.Generic.List<T>.
        //     The collection itself cannot be null, but it can contain elements that are
        //     null, if type T is a reference type.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     collection is null.
        public void AddRange(IEnumerable<T> collection)
        {
            if (this.CanChangeList(ListChangeType.AddRange))
            {
                this._List.AddRange(collection);
                this.OnChangeListAfter(ListChangeType.AddRange);
            }
        }
        //
        // Summary:
        //     Returns a read-only System.Collections.Generic.IList<T> wrapper for the current
        //     collection.
        //
        // Returns:
        //     A System.Collections.ObjectModel.ReadOnlyCollection<T> that acts as a read-only
        //     wrapper around the current System.Collections.Generic.List<T>.
        public ReadOnlyCollection<T> AsReadOnly() { return this._List.AsReadOnly(); }
        //
        // Summary:
        //     Searches the entire sorted System.Collections.Generic.List<T> for an element
        //     using the default comparer and returns the zero-based index of the element.
        //
        // Parameters:
        //   item:
        //     The object to locate. The value can be null for reference types.
        //
        // Returns:
        //     The zero-based index of item in the sorted System.Collections.Generic.List<T>,
        //     if item is found; otherwise, a negative number that is the bitwise complement
        //     of the index of the next element that is larger than item or, if there is
        //     no larger element, the bitwise complement of System.Collections.Generic.List<T>.Count.
        //
        // Exceptions:
        //   System.InvalidOperationException:
        //     The default comparer System.Collections.Generic.Comparer<T>.Default cannot
        //     find an implementation of the System.IComparable<T> generic interface or
        //     the System.IComparable interface for type T.
        public int BinarySearch(T item) { return this._List.BinarySearch(item); }
        //
        // Summary:
        //     Searches the entire sorted System.Collections.Generic.List<T> for an element
        //     using the specified comparer and returns the zero-based index of the element.
        //
        // Parameters:
        //   item:
        //     The object to locate. The value can be null for reference types.
        //
        //   comparer:
        //     The System.Collections.Generic.IComparer<T> implementation to use when comparing
        //     elements.-or-null to use the default comparer System.Collections.Generic.Comparer<T>.Default.
        //
        // Returns:
        //     The zero-based index of item in the sorted System.Collections.Generic.List<T>,
        //     if item is found; otherwise, a negative number that is the bitwise complement
        //     of the index of the next element that is larger than item or, if there is
        //     no larger element, the bitwise complement of System.Collections.Generic.List<T>.Count.
        //
        // Exceptions:
        //   System.InvalidOperationException:
        //     comparer is null, and the default comparer System.Collections.Generic.Comparer<T>.Default
        //     cannot find an implementation of the System.IComparable<T> generic interface
        //     or the System.IComparable interface for type T.
        public int BinarySearch(T item, IComparer<T> comparer) { return this._List.BinarySearch(item, comparer); }
        //
        // Summary:
        //     Searches a range of elements in the sorted System.Collections.Generic.List<T>
        //     for an element using the specified comparer and returns the zero-based index
        //     of the element.
        //
        // Parameters:
        //   index:
        //     The zero-based starting index of the range to search.
        //
        //   count:
        //     The length of the range to search.
        //
        //   item:
        //     The object to locate. The value can be null for reference types.
        //
        //   comparer:
        //     The System.Collections.Generic.IComparer<T> implementation to use when comparing
        //     elements, or null to use the default comparer System.Collections.Generic.Comparer<T>.Default.
        //
        // Returns:
        //     The zero-based index of item in the sorted System.Collections.Generic.List<T>,
        //     if item is found; otherwise, a negative number that is the bitwise complement
        //     of the index of the next element that is larger than item or, if there is
        //     no larger element, the bitwise complement of System.Collections.Generic.List<T>.Count.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-count is less than 0.
        //
        //   System.ArgumentException:
        //     index and count do not denote a valid range in the System.Collections.Generic.List<T>.
        //
        //   System.InvalidOperationException:
        //     comparer is null, and the default comparer System.Collections.Generic.Comparer<T>.Default
        //     cannot find an implementation of the System.IComparable<T> generic interface
        //     or the System.IComparable interface for type T.
        public int BinarySearch(int index, int count, T item, IComparer<T> comparer) { return this._List.BinarySearch(index, count, item, comparer); }
        //
        // Summary:
        //     Removes all elements from the System.Collections.Generic.List<T>.
        public void Clear()
        {
            if (this.CanChangeList(ListChangeType.Clear))
            {
                this._List.Clear();
                this.OnChangeListAfter(ListChangeType.Clear);
            }
        }
        //
        // Summary:
        //     Determines whether an element is in the System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   item:
        //     The object to locate in the System.Collections.Generic.List<T>. The value
        //     can be null for reference types.
        //
        // Returns:
        //     true if item is found in the System.Collections.Generic.List<T>; otherwise,
        //     false.
        public bool Contains(T item) { return this._List.Contains(item); }
        //
        // Summary:
        //     Converts the elements in the current System.Collections.Generic.List<T> to
        //     another type, and returns a list containing the converted elements.
        //
        // Parameters:
        //   converter:
        //     A System.Converter<TInput,TOutput> delegate that converts each element from
        //     one type to another type.
        //
        // Type parameters:
        //   TOutput:
        //     The type of the elements of the target array.
        //
        // Returns:
        //     A System.Collections.Generic.List<T> of the target type containing the converted
        //     elements from the current System.Collections.Generic.List<T>.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     converter is null.
        public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter) { return this._List.ConvertAll(converter); }
        //
        // Summary:
        //     Copies the entire System.Collections.Generic.List<T> to a compatible one-dimensional
        //     array, starting at the beginning of the target array.
        //
        // Parameters:
        //   array:
        //     The one-dimensional System.Array that is the destination of the elements
        //     copied from System.Collections.Generic.List<T>. The System.Array must have
        //     zero-based indexing.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     array is null.
        //
        //   System.ArgumentException:
        //     The number of elements in the source System.Collections.Generic.List<T> is
        //     greater than the number of elements that the destination array can contain.
        public void CopyTo(T[] array) { this._List.CopyTo(array); }
        //
        // Summary:
        //     Copies the entire System.Collections.Generic.List<T> to a compatible one-dimensional
        //     array, starting at the specified index of the target array.
        //
        // Parameters:
        //   array:
        //     The one-dimensional System.Array that is the destination of the elements
        //     copied from System.Collections.Generic.List<T>. The System.Array must have
        //     zero-based indexing.
        //
        //   arrayIndex:
        //     The zero-based index in array at which copying begins.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     array is null.
        //
        //   System.ArgumentOutOfRangeException:
        //     arrayIndex is less than 0.
        //
        //   System.ArgumentException:
        //     The number of elements in the source System.Collections.Generic.List<T> is
        //     greater than the available space from arrayIndex to the end of the destination
        //     array.
        public void CopyTo(T[] array, int arrayIndex) { this._List.CopyTo(array, arrayIndex); }
        //
        // Summary:
        //     Copies a range of elements from the System.Collections.Generic.List<T> to
        //     a compatible one-dimensional array, starting at the specified index of the
        //     target array.
        //
        // Parameters:
        //   index:
        //     The zero-based index in the source System.Collections.Generic.List<T> at
        //     which copying begins.
        //
        //   array:
        //     The one-dimensional System.Array that is the destination of the elements
        //     copied from System.Collections.Generic.List<T>. The System.Array must have
        //     zero-based indexing.
        //
        //   arrayIndex:
        //     The zero-based index in array at which copying begins.
        //
        //   count:
        //     The number of elements to copy.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     array is null.
        //
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-arrayIndex is less than 0.-or-count is less than
        //     0.
        //
        //   System.ArgumentException:
        //     index is equal to or greater than the System.Collections.Generic.List<T>.Count
        //     of the source System.Collections.Generic.List<T>.-or-The number of elements
        //     from index to the end of the source System.Collections.Generic.List<T> is
        //     greater than the available space from arrayIndex to the end of the destination
        //     array.
        public void CopyTo(int index, T[] array, int arrayIndex, int count) { this._List.CopyTo(index, array, arrayIndex, count); }
        //
        // Summary:
        //     Determines whether the System.Collections.Generic.List<T> contains elements
        //     that match the conditions defined by the specified predicate.
        //
        // Parameters:
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the elements
        //     to search for.
        //
        // Returns:
        //     true if the System.Collections.Generic.List<T> contains one or more elements
        //     that match the conditions defined by the specified predicate; otherwise,
        //     false.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        public bool Exists(Predicate<T> match) { return this._List.Exists(match); }
        //
        // Summary:
        //     Searches for an element that matches the conditions defined by the specified
        //     predicate, and returns the first occurrence within the entire System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the element
        //     to search for.
        //
        // Returns:
        //     The first element that matches the conditions defined by the specified predicate,
        //     if found; otherwise, the default value for type T.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        public T Find(Predicate<T> match) { return this._List.Find(match); }
        //
        // Summary:
        //     Retrieves all the elements that match the conditions defined by the specified
        //     predicate.
        //
        // Parameters:
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the elements
        //     to search for.
        //
        // Returns:
        //     A System.Collections.Generic.List<T> containing all the elements that match
        //     the conditions defined by the specified predicate, if found; otherwise, an
        //     empty System.Collections.Generic.List<T>.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        public List<T> FindAll(Predicate<T> match) { return this._List.FindAll(match); }
        //
        // Summary:
        //     Searches for an element that matches the conditions defined by the specified
        //     predicate, and returns the zero-based index of the first occurrence within
        //     the entire System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the element
        //     to search for.
        //
        // Returns:
        //     The zero-based index of the first occurrence of an element that matches the
        //     conditions defined by match, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        public int FindIndex(Predicate<T> match) { return this._List.FindIndex(match); }
        //
        // Summary:
        //     Searches for an element that matches the conditions defined by the specified
        //     predicate, and returns the zero-based index of the first occurrence within
        //     the range of elements in the System.Collections.Generic.List<T> that extends
        //     from the specified index to the last element.
        //
        // Parameters:
        //   startIndex:
        //     The zero-based starting index of the search.
        //
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the element
        //     to search for.
        //
        // Returns:
        //     The zero-based index of the first occurrence of an element that matches the
        //     conditions defined by match, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        //
        //   System.ArgumentOutOfRangeException:
        //     startIndex is outside the range of valid indexes for the System.Collections.Generic.List<T>.
        public int FindIndex(int startIndex, Predicate<T> match) { return this._List.FindIndex(startIndex, match); }
        //
        // Summary:
        //     Searches for an element that matches the conditions defined by the specified
        //     predicate, and returns the zero-based index of the first occurrence within
        //     the range of elements in the System.Collections.Generic.List<T> that starts
        //     at the specified index and contains the specified number of elements.
        //
        // Parameters:
        //   startIndex:
        //     The zero-based starting index of the search.
        //
        //   count:
        //     The number of elements in the section to search.
        //
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the element
        //     to search for.
        //
        // Returns:
        //     The zero-based index of the first occurrence of an element that matches the
        //     conditions defined by match, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        //
        //   System.ArgumentOutOfRangeException:
        //     startIndex is outside the range of valid indexes for the System.Collections.Generic.List<T>.-or-count
        //     is less than 0.-or-startIndex and count do not specify a valid section in
        //     the System.Collections.Generic.List<T>.
        public int FindIndex(int startIndex, int count, Predicate<T> match) { return this._List.FindIndex(startIndex, count, match); }
        //
        // Summary:
        //     Searches for an element that matches the conditions defined by the specified
        //     predicate, and returns the last occurrence within the entire System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the element
        //     to search for.
        //
        // Returns:
        //     The last element that matches the conditions defined by the specified predicate,
        //     if found; otherwise, the default value for type T.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        public T FindLast(Predicate<T> match) { return this._List.FindLast(match); }
        //
        // Summary:
        //     Searches for an element that matches the conditions defined by the specified
        //     predicate, and returns the zero-based index of the last occurrence within
        //     the entire System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the element
        //     to search for.
        //
        // Returns:
        //     The zero-based index of the last occurrence of an element that matches the
        //     conditions defined by match, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        public int FindLastIndex(Predicate<T> match) { return this._List.FindLastIndex(match); }
        //
        // Summary:
        //     Searches for an element that matches the conditions defined by the specified
        //     predicate, and returns the zero-based index of the last occurrence within
        //     the range of elements in the System.Collections.Generic.List<T> that extends
        //     from the first element to the specified index.
        //
        // Parameters:
        //   startIndex:
        //     The zero-based starting index of the backward search.
        //
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the element
        //     to search for.
        //
        // Returns:
        //     The zero-based index of the last occurrence of an element that matches the
        //     conditions defined by match, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        //
        //   System.ArgumentOutOfRangeException:
        //     startIndex is outside the range of valid indexes for the System.Collections.Generic.List<T>.
        public int FindLastIndex(int startIndex, Predicate<T> match) { return this._List.FindLastIndex(startIndex, match); }
        //
        // Summary:
        //     Searches for an element that matches the conditions defined by the specified
        //     predicate, and returns the zero-based index of the last occurrence within
        //     the range of elements in the System.Collections.Generic.List<T> that contains
        //     the specified number of elements and ends at the specified index.
        //
        // Parameters:
        //   startIndex:
        //     The zero-based starting index of the backward search.
        //
        //   count:
        //     The number of elements in the section to search.
        //
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the element
        //     to search for.
        //
        // Returns:
        //     The zero-based index of the last occurrence of an element that matches the
        //     conditions defined by match, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        //
        //   System.ArgumentOutOfRangeException:
        //     startIndex is outside the range of valid indexes for the System.Collections.Generic.List<T>.-or-count
        //     is less than 0.-or-startIndex and count do not specify a valid section in
        //     the System.Collections.Generic.List<T>.
        public int FindLastIndex(int startIndex, int count, Predicate<T> match) { return this._List.FindLastIndex(startIndex, count, match); }
        //
        // Summary:
        //     Performs the specified action on each element of the System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   action:
        //     The System.Action<T> delegate to perform on each element of the System.Collections.Generic.List<T>.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     action is null.
        public void ForEach(Action<T> action) { this._List.ForEach(action); }
        //
        // Summary:
        //     Returns an enumerator that iterates through the System.Collections.Generic.List<T>.
        //
        // Returns:
        //     A System.Collections.Generic.List<T>.Enumerator for the System.Collections.Generic.List<T>.
        public List<T>.Enumerator GetEnumerator() { return this._List.GetEnumerator(); }
        //
        // Summary:
        //     Creates a shallow copy of a range of elements in the source System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   index:
        //     The zero-based System.Collections.Generic.List<T> index at which the range
        //     starts.
        //
        //   count:
        //     The number of elements in the range.
        //
        // Returns:
        //     A shallow copy of a range of elements in the source System.Collections.Generic.List<T>.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-count is less than 0.
        //
        //   System.ArgumentException:
        //     index and count do not denote a valid range of elements in the System.Collections.Generic.List<T>.
        public List<T> GetRange(int index, int count) { return this._List.GetRange(index, count); }
        //
        // Summary:
        //     Searches for the specified object and returns the zero-based index of the
        //     first occurrence within the entire System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   item:
        //     The object to locate in the System.Collections.Generic.List<T>. The value
        //     can be null for reference types.
        //
        // Returns:
        //     The zero-based index of the first occurrence of item within the entire System.Collections.Generic.List<T>,
        //     if found; otherwise, –1.
        public int IndexOf(T item) { return this._List.IndexOf(item); }
        //
        // Summary:
        //     Searches for the specified object and returns the zero-based index of the
        //     first occurrence within the range of elements in the System.Collections.Generic.List<T>
        //     that extends from the specified index to the last element.
        //
        // Parameters:
        //   item:
        //     The object to locate in the System.Collections.Generic.List<T>. The value
        //     can be null for reference types.
        //
        //   index:
        //     The zero-based starting index of the search. 0 (zero) is valid in an empty
        //     list.
        //
        // Returns:
        //     The zero-based index of the first occurrence of item within the range of
        //     elements in the System.Collections.Generic.List<T> that extends from index
        //     to the last element, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is outside the range of valid indexes for the System.Collections.Generic.List<T>.
        public int IndexOf(T item, int index) { return this._List.IndexOf(item, index); }
        //
        // Summary:
        //     Searches for the specified object and returns the zero-based index of the
        //     first occurrence within the range of elements in the System.Collections.Generic.List<T>
        //     that starts at the specified index and contains the specified number of elements.
        //
        // Parameters:
        //   item:
        //     The object to locate in the System.Collections.Generic.List<T>. The value
        //     can be null for reference types.
        //
        //   index:
        //     The zero-based starting index of the search. 0 (zero) is valid in an empty
        //     list.
        //
        //   count:
        //     The number of elements in the section to search.
        //
        // Returns:
        //     The zero-based index of the first occurrence of item within the range of
        //     elements in the System.Collections.Generic.List<T> that starts at index and
        //     contains count number of elements, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is outside the range of valid indexes for the System.Collections.Generic.List<T>.-or-count
        //     is less than 0.-or-index and count do not specify a valid section in the
        //     System.Collections.Generic.List<T>.
        public int IndexOf(T item, int index, int count) { return this._List.IndexOf(item, index, count); }
        //
        // Summary:
        //     Inserts an element into the System.Collections.Generic.List<T> at the specified
        //     index.
        //
        // Parameters:
        //   index:
        //     The zero-based index at which item should be inserted.
        //
        //   item:
        //     The object to insert. The value can be null for reference types.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-index is greater than System.Collections.Generic.List<T>.Count.
        public void Insert(int index, T item)
        {
            if (this.CanAddItem(item, index))
            {
                this._List.Insert(index, item);
                this.OnAddItemAfter(item, index);
            }
        }
        //
        // Summary:
        //     Inserts the elements of a collection into the System.Collections.Generic.List<T>
        //     at the specified index.
        //
        // Parameters:
        //   index:
        //     The zero-based index at which the new elements should be inserted.
        //
        //   collection:
        //     The collection whose elements should be inserted into the System.Collections.Generic.List<T>.
        //     The collection itself cannot be null, but it can contain elements that are
        //     null, if type T is a reference type.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     collection is null.
        //
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-index is greater than System.Collections.Generic.List<T>.Count.
        public void InsertRange(int index, IEnumerable<T> collection)
        {
            if (this.CanChangeList(ListChangeType.AddRange, default(T), index))
            {
                this._List.InsertRange(index, collection);
                this.OnChangeListAfter(ListChangeType.AddRange, default(T), index);
            }
        }
        //
        // Summary:
        //     Searches for the specified object and returns the zero-based index of the
        //     last occurrence within the entire System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   item:
        //     The object to locate in the System.Collections.Generic.List<T>. The value
        //     can be null for reference types.
        //
        // Returns:
        //     The zero-based index of the last occurrence of item within the entire the
        //     System.Collections.Generic.List<T>, if found; otherwise, –1.
        public int LastIndexOf(T item) { return this._List.LastIndexOf(item); }
        //
        // Summary:
        //     Searches for the specified object and returns the zero-based index of the
        //     last occurrence within the range of elements in the System.Collections.Generic.List<T>
        //     that extends from the first element to the specified index.
        //
        // Parameters:
        //   item:
        //     The object to locate in the System.Collections.Generic.List<T>. The value
        //     can be null for reference types.
        //
        //   index:
        //     The zero-based starting index of the backward search.
        //
        // Returns:
        //     The zero-based index of the last occurrence of item within the range of elements
        //     in the System.Collections.Generic.List<T> that extends from the first element
        //     to index, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is outside the range of valid indexes for the System.Collections.Generic.List<T>.
        public int LastIndexOf(T item, int index) { return this._List.LastIndexOf(item, index); }
        //
        // Summary:
        //     Searches for the specified object and returns the zero-based index of the
        //     last occurrence within the range of elements in the System.Collections.Generic.List<T>
        //     that contains the specified number of elements and ends at the specified
        //     index.
        //
        // Parameters:
        //   item:
        //     The object to locate in the System.Collections.Generic.List<T>. The value
        //     can be null for reference types.
        //
        //   index:
        //     The zero-based starting index of the backward search.
        //
        //   count:
        //     The number of elements in the section to search.
        //
        // Returns:
        //     The zero-based index of the last occurrence of item within the range of elements
        //     in the System.Collections.Generic.List<T> that contains count number of elements
        //     and ends at index, if found; otherwise, –1.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is outside the range of valid indexes for the System.Collections.Generic.List<T>.-or-count
        //     is less than 0.-or-index and count do not specify a valid section in the
        //     System.Collections.Generic.List<T>.
        public int LastIndexOf(T item, int index, int count) { return this._List.LastIndexOf(item, index, count); }
        //
        // Summary:
        //     Removes the first occurrence of a specific object from the System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   item:
        //     The object to remove from the System.Collections.Generic.List<T>. The value
        //     can be null for reference types.
        //
        // Returns:
        //     true if item is successfully removed; otherwise, false. This method also
        //     returns false if item was not found in the System.Collections.Generic.List<T>.
        public bool Remove(T item)
        {
            bool result = false;
            if (this.CanRemoveItem(item, null))
            {
                result = this._List.Remove(item);
                this.OnRemoveItemAfter(item, null);
            }
            return result;
        }
        //
        // Summary:
        //     Removes the all the elements that match the conditions defined by the specified
        //     predicate.
        //
        // Parameters:
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions of the elements
        //     to remove.
        //
        // Returns:
        //     The number of elements removed from the System.Collections.Generic.List<T>
        //     .
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        public int RemoveAll(Predicate<T> match)
        {
            int result = -1;
            if (this.CanChangeList(ListChangeType.RemoveAll))
            {
                result = this._List.RemoveAll(match);
                this.OnChangeListAfter(ListChangeType.RemoveAll);
            }
            return result;
        }
        //
        // Summary:
        //     Removes the element at the specified index of the System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   index:
        //     The zero-based index of the element to remove.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-index is equal to or greater than System.Collections.Generic.List<T>.Count.
        public void RemoveAt(int index)
        {
            T item = ((index >= 0 && index < this._List.Count) ? this._List[index] : default(T));
            if (this.CanRemoveItem(item, index))
            {
                this._List.RemoveAt(index);
                this.OnRemoveItemAfter(item, index);
            }
        }
        //
        // Summary:
        //     Removes a range of elements from the System.Collections.Generic.List<T>.
        //
        // Parameters:
        //   index:
        //     The zero-based starting index of the range of elements to remove.
        //
        //   count:
        //     The number of elements to remove.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-count is less than 0.
        //
        //   System.ArgumentException:
        //     index and count do not denote a valid range of elements in the System.Collections.Generic.List<T>.
        public void RemoveRange(int index, int count)
        {
            if (this.CanChangeList(ListChangeType.RemoveAll))
            {
                this._List.RemoveRange(index, count);
                this.OnChangeListAfter(ListChangeType.RemoveAll);
            }
        }
        //
        // Summary:
        //     Reverses the order of the elements in the entire System.Collections.Generic.List<T>.
        public void Reverse()
        {
            if (this.CanChangeList(ListChangeType.ChangeOrder))
            {
                this._List.Reverse();
                this.OnChangeListAfter(ListChangeType.ChangeOrder);
            }
        }
        //
        // Summary:
        //     Reverses the order of the elements in the specified range.
        //
        // Parameters:
        //   index:
        //     The zero-based starting index of the range to reverse.
        //
        //   count:
        //     The number of elements in the range to reverse.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-count is less than 0.
        //
        //   System.ArgumentException:
        //     index and count do not denote a valid range of elements in the System.Collections.Generic.List<T>.
        public void Reverse(int index, int count)
        {
            if (this.CanChangeList(ListChangeType.ChangeOrder))
            {
                this._List.Reverse(index, count);
                this.OnChangeListAfter(ListChangeType.ChangeOrder);
            }
        }
        //
        // Summary:
        //     Sorts the elements in the entire System.Collections.Generic.List<T> using
        //     the default comparer.
        //
        // Exceptions:
        //   System.InvalidOperationException:
        //     The default comparer System.Collections.Generic.Comparer<T>.Default cannot
        //     find an implementation of the System.IComparable<T> generic interface or
        //     the System.IComparable interface for type T.
        public void Sort()
        {
            if (this.CanChangeList(ListChangeType.ChangeOrder))
            {
                this._List.Sort();
                this.OnChangeListAfter(ListChangeType.ChangeOrder);
            }
        }
        //
        // Summary:
        //     Sorts the elements in the entire System.Collections.Generic.List<T> using
        //     the specified System.Comparison<T>.
        //
        // Parameters:
        //   comparison:
        //     The System.Comparison<T> to use when comparing elements.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     comparison is null.
        //
        //   System.ArgumentException:
        //     The implementation of comparison caused an error during the sort. For example,
        //     comparison might not return 0 when comparing an item with itself.
        public void Sort(Comparison<T> comparison)
        {
            if (this.CanChangeList(ListChangeType.ChangeOrder))
            {
                this._List.Sort(comparison);
                this.OnChangeListAfter(ListChangeType.ChangeOrder);
            }
        }
        //
        // Summary:
        //     Sorts the elements in the entire System.Collections.Generic.List<T> using
        //     the specified comparer.
        //
        // Parameters:
        //   comparer:
        //     The System.Collections.Generic.IComparer<T> implementation to use when comparing
        //     elements, or null to use the default comparer System.Collections.Generic.Comparer<T>.Default.
        //
        // Exceptions:
        //   System.InvalidOperationException:
        //     comparer is null, and the default comparer System.Collections.Generic.Comparer<T>.Default
        //     cannot find implementation of the System.IComparable<T> generic interface
        //     or the System.IComparable interface for type T.
        //
        //   System.ArgumentException:
        //     The implementation of comparer caused an error during the sort. For example,
        //     comparer might not return 0 when comparing an item with itself.
        public void Sort(IComparer<T> comparer)
        {
            if (this.CanChangeList(ListChangeType.ChangeOrder))
            {
                this._List.Sort(comparer);
                this.OnChangeListAfter(ListChangeType.ChangeOrder);
            }
        }
        //
        // Summary:
        //     Sorts the elements in a range of elements in System.Collections.Generic.List<T>
        //     using the specified comparer.
        //
        // Parameters:
        //   index:
        //     The zero-based starting index of the range to sort.
        //
        //   count:
        //     The length of the range to sort.
        //
        //   comparer:
        //     The System.Collections.Generic.IComparer<T> implementation to use when comparing
        //     elements, or null to use the default comparer System.Collections.Generic.Comparer<T>.Default.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-count is less than 0.
        //
        //   System.ArgumentException:
        //     index and count do not specify a valid range in the System.Collections.Generic.List<T>.-or-The
        //     implementation of comparer caused an error during the sort. For example,
        //     comparer might not return 0 when comparing an item with itself.
        //
        //   System.InvalidOperationException:
        //     comparer is null, and the default comparer System.Collections.Generic.Comparer<T>.Default
        //     cannot find implementation of the System.IComparable<T> generic interface
        //     or the System.IComparable interface for type T.
        public void Sort(int index, int count, IComparer<T> comparer)
        {
            if (this.CanChangeList(ListChangeType.ChangeOrder))
            {
                this._List.Sort(index, count, comparer);
                this.OnChangeListAfter(ListChangeType.ChangeOrder);
            }
        }
        //
        // Summary:
        //     Copies the elements of the System.Collections.Generic.List<T> to a new array.
        //
        // Returns:
        //     An array containing copies of the elements of the System.Collections.Generic.List<T>.
        public T[] ToArray() { return this._List.ToArray(); }
        //
        // Summary:
        //     Sets the capacity to the actual number of elements in the System.Collections.Generic.List<T>,
        //     if that number is less than a threshold value.
        public void TrimExcess() { this._List.TrimExcess(); }
        //
        // Summary:
        //     Determines whether every element in the System.Collections.Generic.List<T>
        //     matches the conditions defined by the specified predicate.
        //
        // Parameters:
        //   match:
        //     The System.Predicate<T> delegate that defines the conditions to check against
        //     the elements.
        //
        // Returns:
        //     true if every element in the System.Collections.Generic.List<T> matches the
        //     conditions defined by the specified predicate; otherwise, false. If the list
        //     has no elements, the return value is true.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     match is null.
        public bool TrueForAll(Predicate<T> match) { return this._List.TrueForAll(match); }
        #endregion
        private List<T> _List;
        #region IEnumerable Members
        IEnumerator<T> IEnumerable<T>.GetEnumerator() { return this._List.GetEnumerator(); }
        IEnumerator IEnumerable.GetEnumerator() { return this._List.GetEnumerator(); }
        #endregion
    }
    /// <summary>
    /// Typ změny
    /// </summary>
    public enum ListChangeType
    {
        None,
        Add,
        AddRange,
        Get,
        Set,
        Remove,
        RemoveAll,
        ChangeOrder,
        Clear
    }
    #endregion
}
